#ifndef custom_string_c
#define custom_string_c

#include "custom_string.h"
#include "mesinkata.h"
#include "string.h"

string StrCat(string s1, string s2)
/* Menggabungkan 2 string */
{
    //Kamus Lokal
    //string s = s1;
    int i = s1.length , j = 0;
    //Algoritma
    while (s2.s[j] != '\0')
    {
        s1.s[i] = s2.s[j];
        i++; j++;
    }
    s1.s[i] = '\0';
    s1.length = i;
    return s1;
}

//--------------
//  RELASIONAL
//--------------
boolean IsStringEq(string k1 , string k2)
/* Mengecek kesamaan dari 2 buah string */
{
    int i;
    i = 0;
    if(k1.length != k2.length)
        return false;
    else
    {
        while(i < k1.length && k1.s[i] == k2.s[i])
            i++;
        return (k1.s[i] == k2.s[i]);
    }
}

boolean IsStringLt(string s1 , string s2)
/* Mengecek apakah s1 lebih kecil daripada s2 secara alfabetikal 
misal : ab < abc */
{
	//kamus lokal
    boolean End;
	int i;
	
	//algoritma
	End = false;
	
	if (s1.length == s2.length)
	{
		i = 0;
		while (i < s1.length)
		{
			if (s1.s[i] == s2.s[i])
			{
				i++;
			}
			else if (s1.s[i] < s2.s[i])
			{
				i = s1.length;
			}
			else
			{
				End = true;
				i = s1.length;
			}
		}
	}
	else if (s1.length < s2.length)
	{
		End = false;
	}
	else
	{
		End = true;
	}
	
	return(!End);
}

boolean IsStringGt(string s1 , string s2)
/* Mengecek apakah s1 lebih besar daripada s2 secara alfabetikal 
misal : az > abc */
{
	//kamus lokal
    boolean End;
	int i;
	
	//algoritma
	End = false;
	
	if (s1.length == s2.length)
	{
		i = 0;
		while (i < s1.length)
		{
			if (s1.s[i] == s2.s[i])
			{
				i++;
			}
			else if (s1.s[i] > s2.s[i])
			{
				i = s1.length;
			}
			else
			{
				End = true;
				i = s1.length;
			}
		}
	}
	else if (s1.length > s2.length)
	{
		End = false;
	}
	else
	{
		End = true;
	}
	
	return(!End);
}

int IsStringEqSpec(string s1 , string s2)
/* Mengecek kesamaan dari 2 buah string dengan aturan :
    1. 	pengecekan string dilakukan secara case insensitive
    2. 	mengembalikan nilai 1 jika string sama persis,
        0 jika sangat beda
    3.	,dan 2 jika string hanya berbeda sedikit (butuh algorima LCS (Longest Common Subsequence))
        misal
            IsStringEqSpec("delete","drlete") akan menghasilkan 2
            IsStringEqSpec("indonesia","indonesa") akan menghasilkan 2
    // catatan : poin 3 susah, bisa dilakukan belakangan
    // catatan : s2 adalah string pembanding
    */
{
	int retval=0,lcs;
	string temp,temp2;

	temp  = UpperCase(s1);
	temp2 = UpperCase(s2);
	lcs=LCS(temp,temp2);

	if (IsStringEq(temp,temp2)) {
		retval=1;
		}
	else if (((s2.length>=7)&&((s2.length-lcs)<=3)&&((s1.length-lcs)<=3))
		||((s2.length<=3)&&((s2.length-lcs)<=1)&&((s1.length-lcs)<=1))
		||((s2.length>3)&&(s2.length<=6)&&((s2.length-lcs)<=2)&&((s1.length-lcs)<=2))
		) {
		retval=2;
		}
	
	//printf("LCS = %d\n",lcs);
	
	return retval;
}

int maxx (int a, int b) 
/* menghasilkan nilai maksimum dari a dan b */
{
	if (a>b) return a;
	else return b;
}

int LCS (string s1, string s2) 
/*  mengeluarkan panjang longest common subsequence dari string s1 dan string s2 */
{
	int lcs[255][255],i,j;

	//inisiasi tabel
	for (i=0;i<255;i++) {for (j=0;j<255;j++) {lcs[i][j]=0;}}
	for (i=1;i<=s1.length;i++) {
		for (j=1;j<=s2.length;j++) {
			if (s1.s[i]==s2.s[j]) 
				{lcs[i][j] = 1 + lcs[i-1][j-1];}
			else {
				lcs[i][j]=maxx(lcs[i-1][j],lcs[i][j-1]);
			}
		}	
	}
	return lcs[s1.length][s2.length];
}


//--------------
//  Pengecekan Tambahan Tipe String
//--------------
boolean IsNumber(char C)
/* true jika C adalah bilangan */
{return ('0' <= C) && (C <= '9');}

boolean IsStringDir (string S)
/* mengecek apakah string adalah suatu direktori atau bukan 
direktori diawali dengan '/' di linux, 'X:\' di windows  */
{return (S.s[0] == '/');}

boolean IsStringFormula (string S)
/* mengecek apakah string adalah suatu formula atau bukan 
formula selalu diawali dengan = */
{return (S.s[0] == '=');}

boolean IsStringInteger (string S)
/* mengecek apakah string dapat diubah menjadi suatu Integer atau tidak 
Integer selalu berisi angka (1-9) dengan nilai diantara -2 milyar dan 2 milyar inklusif */
{
    //Kamus Lokal
    int i = 0;
    //Algoritma
    boolean isNum = true , firstchar = true;
    while (i < S.length)
    {
        isNum = isNum && (IsNumber(S.s[i]) || (S.s[i] == '-' && firstchar));
        if (S.s[i] == '-' && firstchar)
            firstchar = false;
        i++;
    }
    return isNum;
}

boolean IsStringDouble (string S)
/* mengecek apakah string dapat diubah menjadi bilangan double atau tidak 
double selalu berisi angka (1-9) dengan nilai diantara -2 milyar dan 2 milyar inklusif dan
tepat 1 buah titik*/
{
    //Kamus Lokal
    int i = 0;
	int dot=0;
    boolean isNum = true , isDouble = false , firstchar = true;
    //Algoritma
    while (i < S.length)
    {
        isNum = isNum && (IsNumber(S.s[i]) || S.s[i] == '.' || (S.s[i] == '-' && firstchar));
        if (S.s[i] == '-' && firstchar)
            firstchar = false;
        if (S.s[i] == '.'){
            isDouble = true;
			dot++;
			}
        i++;
    }
	if (dot>1) {
		return false; }
	else 
		return isDouble || isNum;
}

boolean IsStringBoolean (string S)
/* mengecek apakah string dapat diubah menjadi boolean atau tidak 
boolean hanya berisi 2 macam data true atau false (case_insensitive) atau tipe data integer */
/* BELOM CASE SENSITIVE INI */
{
    //Kamus lokal
    //Algoritma
    if ((IsStringEqSpec(S,CharToString("true"))==1)||
        (IsStringEqSpec(S,CharToString("false"))==1))
        return true;
    else
        return false;
}

boolean IsStringDate (string S)
/* mengecek apakah string dapat diubah menjadi tipe bentukan date yang valid atau tidak 
tipe date yang valid selalu berformat dd-mm-yy , dan merupakan tanggal yang valid*/
{
    int DD,MM,YY;
    boolean retval = false, valid = false;
    if (S.s[2] == '-' && S.s[5] == '-' &&
        IsNumber(S.s[0]) && IsNumber(S.s[1]) &&
        IsNumber(S.s[3]) && IsNumber(S.s[4]) &&
        IsNumber(S.s[6]) && IsNumber(S.s[7]))
    {
        retval = true;
        DD = (S.s[0]-'0')*10 + (S.s[1]-'0');
        MM = (S.s[3]-'0')*10 + (S.s[4]-'0');
        YY = (S.s[6]-'0')*10 + (S.s[7]-'0');
        if (//Jan,Mar,May,Jul,Aug,Oct,Dec
            (DD >= 0 && DD <= 31 && (MM == 1||MM == 3||MM == 5||MM == 7||MM == 8||MM == 10||MM == 12))
            ||//Apr,Jun,Sept,Nov
            (DD >= 0 && DD <= 30 && (MM == 4||MM == 6||MM == 9||MM == 11))
            ||//Feb, Kabisat
            (DD >= 0 && DD <= 29 && MM == 2 && (YY%4 == 0 || (YY%4 != 0 && YY%400 == 0)))
            ||//Feb, Non Kanisat
            (DD >= 0 && DD <= 28 && MM == 2 && (!(YY%4 == 0 || (YY%4 != 0 && YY%400 == 0))))
           )
            valid = true;
        return valid&&retval;
    }
}

boolean IsStringTime (string S)
/* mengecek apakah string dapat diubah menjadi tipe bentukan time yang valid atau tidak 
tipe time yang valid selalu berformat hh:mm:ss , dan merupakan waktu yang valid 
dalam format 24 jam 00:00:00-23:59:59 */
{
    if (S.s[2] == ':' && S.s[5] == ':' &&
        IsNumber(S.s[0]) && IsNumber(S.s[1]) &&
        IsNumber(S.s[3]) && IsNumber(S.s[4]) &&
        IsNumber(S.s[6]) && IsNumber(S.s[7]) &&
        ((S.s[0] == '2' && S.s[1] <= '3') || (S.s[0] <= '1' && S.s[1] <= '9') &&
         (S.s[3] <= '5' && S.s[4] <= '9' && S.s[6] <= '5' && S.s[7] <= '9'))
       )
        return true;
    else return false;
}

//--------------
// KONVERTER
//--------------

// Konversi string <-->  integer
int StringToInt(string s)
{
	return(atoi(s.s));
    /* //Kamus lokal
    int result = 0 , i = 0 , sign = 1;
    //Algoritma
    while (i < s.length)
    {
        if (s.s[i] >= '0' && s.s[i] <= '9' && result != 999999999)
            result = result*10 + (s.s[i] - '0');
        else if (s.s[i] == '-')
                sign = -1;
        else if (s.s[i] != BLANK)
        {
            result = 999999999;
            sign = -1;
        }
        i++;
    }
    return (sign*result); */
}

string IntToString(long x)
{
    string s;
    int  i = 0;
    sprintf(s.s , "%ld" , x);
    while (s.s[i] != '\0')
        i++;
    s.length = i;
    return s;
}

// Konversi array of char <--> string
char *StringToChar(string s)
{
    char *temp = (char *) malloc(sizeof (char) * s.length);
    sprintf(temp , "%s" , s.s);
    return temp;
}

string CharToString(char *c)
{
    int i;
    string s;
    i = 0;
    while (c[i] != '\0')
    {
        s.s[i] = c[i];
        i++;
    }
    s.length = i;
    s.s[i] = '\0';
    return s;
}

// Konversi string <--> real
double StringToDouble(string s)
{
	return(atof(s.s));
    /* //Kamus Lokal
    int i = 0;
    float result = 0 , mul = 1;
    int sign = 1;
    //Algoritma
    while (s.s[i] != '.' && i < s.length)
    {
        if (s.s[i] != '-')
            result = result*10 + (s.s[i] - '0');
        if (s.s[i] == '-' && i == 0)
             sign = -1;
        i++;
    }
    if (s.s[i] == '.')
    {
        i++;
        while (i < s.length)
        {
            mul *= 0.1;
            result = result + mul * (s.s[i] - '0');
            i++;
        }
    }
    else {}
    return (sign*result); */
}

string DoubleToString(double x)
{
    char temp[100];
    boolean isReal = false;
    sprintf(temp , "%lf" , x);

    return CharToString(temp);
}

// Konversi string <--> boolean
boolean StringToBool(string s)
{
    //Kamus lokal
    //Algoritma
    if (IsStringEqSpec(s,CharToString("true"))==1)
        return true;
    else if (IsStringEqSpec(s,CharToString("false"))==1)
        return false;
    else
    {}
}

string BoolToString(boolean x)
{
	string s;
    if (x == true)
    {
	s=CharToString("true");
	}
    else
    {
        s=CharToString("false");
    }
    return(s);
}

//--------------
//  OPERATOR
//--------------

string GetSubString(string s, int start, int length)
/* Mengambil substring dari string s dari posisi start sepanjang length */
{
    int i,j;
    j = 0;
    string temp;
    for (i = start; i <= start+length-1; i++)
    {
        temp.s[j] = s.s[i];
        j++;
    }
    temp.s[j]='\0';
    temp.length=j;
    return temp;
}

string UpperCase(string s)
/* Mengembalikan string s dengan setiap elemen string s adalah uppercase */
{
    int i;
    for(i = 0; s.s[i]!='\0'; i++)
    {
        //ASCII 'a' - 'z' = 97 - 122
        if (s.s[i] >= 'a' && s.s[i] <= 'z')
            s.s[i] = s.s[i]-32;
    }
    return s;
}

string LowerCase(string s)
/* Mengembalikan string s dengan setiap elemen string s adalah lowercase */
{
    int i;
    for(i = 0; s.s[i]!='\0'; i++)
    {
        //ASCII 'A' - 'Z' = 65 - 90
        if (s.s[i] >= 'A' && s.s[i] <= 'Z')
            s.s[i] = s.s[i]+32;
    }
    return s;
}

string TrimWhiteSpace(string s)
/* Menghilangkan semua spasi dari string s */
{
    string temp;
    int i,j;
    i = 0; j = i;
    for (i = 0; i < s.length; i++)
    {
        if (s.s[i] != ' ')
            temp.s[j] = s.s[i];
        j++;
    }
    temp.length = j;
    temp.s[j] = '\0';
    return temp;
}

string DeleteSubString(const string s, int pos , int length)
/* menghapus substring dari string s dari posisi pos sepanjang length */
{
    int i,j;
    i = 0; j = i;
    string temp;
    
    while (s.s[j]!= '\0')
    {
        if (j == pos)
        {
            j = pos+length;
            temp.s[i] = s.s[j];
            i++;
            j++;
        }
        else
        {
            temp.s[i] = s.s[j];
            i++; j++;
        }
    }
	temp.s[i]='\0';    
	temp.length=i;
	return temp;
}

#endif


